索引

索引出现的目的就是为了提高数据查询的效率,类似于字典的目录。
实现索引有多种方式(索引模型)。常见的有三种:哈希表、有序数组、搜索树。

哈希表

哈希表是一种以键-值(key-value)存储数据的结构,只要输入待查找的key就可以找到其对应的value。
哈希的思路很简单,把值放在数组里,用一个哈希函数吧key换算成一个确定的位置,然后把value放在数组的这个位置上。
如果出现多个key经过哈希换算后得到同一个值,为了处理这种情况,需要拉出一个链表。
因为哈希表并不强制要求索引的值是有序的,因此使用哈希索引做区间查询速度是很慢的。
因此哈希表结构适用于等值查询的场景,比如memcached和一些nosql引擎。、

有序数组

有序数组在等值查询和范围查询中的性能就都很优秀。
但是在更新数据的时候,由于所有的数据都是有序的,所以当插入一条数据的时候,就必须挪动其后所有的记录,成本非常高。
所以,有序数组索引只适用于静态存储引擎,比如按日统计数据,之前不会再有新的数据插入。

搜索树

二叉搜索树的特点在于:每个节点的左子节点小于父节点,父节点又小于右子节点。时间复杂度是O(log(N))。
为了维持O(log(N))的查询复杂度,就需要保证这棵树是平衡二叉树。为了做这个保证,更新的事件复杂度也是O(log(N))。
多叉树就是每个节点有多个子节点,子节点之间保证从左到右依次递增。
二叉树是搜索效率最高的,但是实际上大多数数据库存储都不会使用二叉树,因为索引不止存在于内存中,还得写在磁盘上。
假设一颗100w节点的平衡二叉树,树高20。一次查询需要访问20个数据模块。假设机械硬盘读取一个模块需要10ms,那么查询一次就需要200ms。
为了让一个查询尽量少读磁盘,就必须让查询过程中尽量少访问数据块。因此多叉树是最好的选择。

InnoDB的索引模型

在InnoDB中,表都是根据主键顺序以索引的形式存放的,这种存储方式的表称之为索引组织表。
InnoDB使用B+树索引模型。每个索引在InnoDB里面对应一颗B+树。
主键索引的叶子节点存的是整行数据,也称之为聚簇索引(clustered index)。根据主键索引进行查询,只需要查询主键的B+树。
非主键索引的叶子内容是主键索引的值,也称之为二级索引(secondary index)。根据非主键索引进行查询,需要先查询非主键索引B+树得到主键的值,然后再查询主键索引的B+树。这个过程称之为回表。
基于非主键索引的查询需要多扫描一颗索引树。因此在查询中尽量使用主键查询。

索引维护

B+数为了维护索引有序性,需要在插入新值的时候根据索引的大小挪动其之后的数据,空出位置。
如果需要变动的数据页已满,这时候就需要申请一个新的数据页,然后挪动不分数据过去,称之为页分裂。页分裂除了影响性能,还影响数据页的利用率。原本放在一页的数据分到了两页中,整体空间占用率降低了大约50%。
当两个相邻的页由于删除了数据,利用率很低之后,就会进行数据页合并。合并的过程相当于分裂的逆过程。
因此建议在绝大多数情况下使用自增索引(根据实际情况选择)。 NOT NULL PRIMARY KEY AUTO_INCREMENT

蒜蓉酱配方

蒜子 20斤
盐 10克
耗油 100克
糖 200克
味精100克
鸡汁50克
鲍鱼汁50克
海鲜酱油20克
白芝麻30克
蒜蓉辣酱1000克

蒜子全部打碎,用清水沥干防止发苦。
然后加上面所有的调料下锅小火熬制到没有辣味了可以出锅。

事务隔离

先说概念,事务就是要保证一组数据操作的原子性,要么全部成功,要么全部失败。
在mysql中,事务支持是由引擎层实现的。比如MyISAM就不支持事务。

隔离性和隔离级别

当数据库上有多个事务同时执行的时候,就可能出现脏读(dirty read)、不可重复读(non-repeatable read)、幻读(phantom read),为了解决这些问题就有了隔离级别。
因为隔离级别越高,效率越低,所以需要找到一个合适的级别。sql标准事务隔离级别包括:读未提交(read uncommitted)、读提交(read commited)、可重复读(repeatable read)、串行化(serializable)。
– 读未提交:指一个事物还没有提交时,他做的改变就能被别的事务看到。
– 读提交: 指一个事物提交后,他做的改变才能被别的事务看到。
– 可重复读: 一个事物执行过程中看到的数据和其启动时看到的数据是一致的,未提交的变更对其他事务不可见。
– 串行化: 对一行记录进行读写操作时都会上锁,后续的读写必须等待前一个事务结束后才能继续执行。
在不同的隔离级别下,数据库行为是不同的。一般默认使用READ_COMMITED。
配置方式是,将启动参数transaction-isolation的值配置为READ-COMMITED。(读提交)
可以使用 show variables来查看当前配置的值。

事务隔离的实现

mysql中每条记录更新的时候会同时记录一条回滚操作。记录上最新的值都可以通过回滚操作算出前一个状态的值。
回滚的日志在没有事务在使用的时候就会被系统回收掉。
因此,长事务会导致很久之前的旧日志无法释放掉,占用大量的存储空间。
mysql5.5及之前的版本,回滚日志是和数据字典放在ibdata文件里的,即时长事务最终提交了,日志文件被清理了但文件也不会变小。
如果想清理回滚段就只能重新建库。
除了对回滚段的影响,长事务还占用锁资源,有可能拖垮整个库。

事务的启动方式

  1. 显式启动事务语句,begin和start transaction。配套的提交语句是commit,回滚是rollback。
  2. set autocommit=0,这个命令会将这个线程的自动提交关掉。即时你执行了一条select语句,事务就会启动,直到你主动执行commit或者rollback,或者断开连接。
    因为第二种方式很容易产生事务,一旦不注意使用就会产生长事务。因此建议设置set autocommit=1,通过显式语句启动事务。

你可以通过information_schema库中的innodb_trx这个表查询长事务。

select * from information_schema.innodb_trx where TIME_TO_SEC(timediff(now(), trx_started))>60

sql更新语句执行过程

首先,列一条最简单的更新语句:

update user set age = 1 where uid = 1;

更新操作和查询不同的地方在于其涉及到两个日志模块:redo logbin log

redo log

由于每次更新操作都需要写入磁盘,磁盘也需要找到对应的记录进行更新,整个过程的io/查询成本都非常高。
WAL(Write-Ahead Logging)技术就用于解决这个问题。他的关键点就是先写日志,再写磁盘。
具体来说,当有一条更新记录的时候,InnoDB就会吧记录写到redo log中,并更新内存,结束更新操作。
同时,InnoDB会在系统空闲的时候将操作记录更新到磁盘中。
但是InnoDB中的redo log大小是固定的。假设配置为4个文件一组,每个文件大小是1GB,那么总容量就是4GB。
从文件头开始写,写到末尾再到开头进行循环操作。
write_pos指针记录当前记录位置,一边写一边后移。
check_point指针记录擦除的位置,一边擦除一边后移,在擦除前要将记录更新到磁盘上。
write_pos 和 check_point 之间的空间就是实际可写入redo log 的大小。
如果大量更新操作占满了redo log的空间,那么就需要阻塞更新操作来擦除redo log上的记录。
有了redo log,InnoDB即时出现异常重启,之前提交的记录也不会丢失,这个能力称之为crash-safe。

bin log

最开始,mysql自带的MyISAM是没有crash-safe能力的,binlog只能用于归档。InnoDB是以插件形式引入mysql的,所以InnoDB有另一套日志系统redo log来实现crash-safe的功能。
binlog作为server层的日志,记录所有的增删改操作。
两种日志的不同点在于:
– redo log是InnoDB特有的;binlog是Mysql的server层实现的,不依赖于任何引擎。
– redo log是物理日志,记录修改的内容;binlog是逻辑日志,记录语句的原始逻辑。
– redo log是循环写,空间有限;binlog是可以一直追加的,不会去擦除以前的日志。

接下来看执行update语句的挫啊做流程。
1. 执行器找到uid = 1的这一行
2. 执行器拿到引擎给的数据,将age的值修改为1,再调用引擎接口写入这行新数据
3. 引擎将这行新数据更新到内存,同事更新这个操作到redo log,记录为prepare状态,然后告知执行器执行完成了,随时可以提交事务
4. 执行器生成这个操作的binlog,并将binlog写入磁盘
5. 执行器调用引擎的事务接口,吧redo log改成commit状态,更新完成。
以上将redo log的操作分为两段提交的目的在于保证两份日志的逻辑一致。

innodb_flush_log_at_trx_commit参数设为1时,每次事务的redo log都会直接持久化到磁盘,即时mysql异常重启后数据也不会丢失。
sync_binlog 参数设为1时,每次事务binlog都持久化到磁盘,保证mysql异常重启后,binlog不会丢失。

sql查询语句执行过程

#sql语句执行过程

首先,了解mysql的几个概念

  • 连接器:管理连接和权限验证
  • 分析器:词法和语法的分析
  • 优化器:生成执行计划,选择索引
  • 执行器:操作存储引擎接口,并返回操作结果
  • 查询缓存:对查询过的结果进行缓存
  • 存储引擎:存储数据,提供读写接口

我们把以上功能进行划分,可以吧mysql分为系统层和存储层。
系统层包括连接器、分析器、优化器、执行器和存储缓存。mysql的大多数核心功能和内置函数都在这一层上,比如存储过程、触发器、视图等。
存储层的存储引擎负责数据管理。目前常用的是MyISAM、InnoDB、Memory等。

下面对以下的sql语句进行分析,看看它的具体操作流程是怎么样的。

select * from user where uid = 1;

连接器

首先,程序将连接到数据库,这时候连接器就会对连接请求进行验证,然后获取操作权限并管理连接。例如:

mysql -h 127.0.0.1 -P 3306 -u mysql -p

当你成功建立连接后,这条连接就会保持住,直到你主动断开链接,或者在长时间没有动作后系统自动断开。这个时间是由wait_timeout参数控制的,默认8小时。
你可以通过 show processlist 命令产看当前的链接状态。
建立连接通常会消耗较多的系统资源,所以在开发过程中需要尽量避免频繁建立连接。
但是如果全部使用长连接,会导致内存使用率上升。因为mysql执行时使用的内存在断开连接的时候才会释放,如果内存占满就会被系统强行终止。
目前有两个比较常用的解决方案:
1. 定时断开长连接,或者在执行大量数据查询后断开连接。
2. 如果版本>5.7,可以使用`mysql_rest_connection来初始化连接。

查询缓存

在建立连接之后,mysql获取到查询请求,会先到查询缓存中检查之前有没有执行过这条命令。
之前执行过的语句及其结果会以key-value的形式缓存到内存中。key是查询语句,value是查询结果。
如果mysql找到了对应的缓存,则会将value直接返回给客户端。如果没有找到,就会继续执行后面的阶段。
但是一般情况下,不建议开启查询缓存。只要一张表的内容产生更新,这张表的缓存都会被清空。除非是一张比较大静态表,才适合使用查询缓存。
通过设置参数query_cache_typeDEMAND来设定默认不使用查询缓存。这是如果你想使用的话可以显式的指定。

select SQL_CACHE * from user where uid = 1;

另外,mysql8.0版本直接把查询缓存这个功能模块删掉了,也就是说未来mysql将不在支持使用查询缓存这个功能。

分析器

mysql开始对你的语句进行“词法分析”,从你输出的select关键字识别出这是一个查询语句;把user识别为表名;把uid识别为列名。
做完“词法分析”后,再进行“语法分析”,判断这个sql语句是否符合MYSQL的语法规范。如果语句不对则抛出异常并结束操作。

优化器

经过分析器后,mysql系统就知道你要做什么了。接下来在执行实际的查询之前,需要对执行的操作进行选择。
优化器是在表里有多个索引的时候,选择使用哪个索引;在一个语句有多表关联的时候,决定表的连接顺序。优化器会根据已有的索引、表的大小、字段长度等信息决定一个最优的查询方案。

执行器

当mysql系统确定好执行方案后,通过执行器调用存储引擎的操作接口开始进行数据的查询操作。
在开始执行的时候,回对当前的用户是否具备执行权限进行判断。如果没有就会返回权限提示。如果正常则会继续执行。
打开表的时候,执行器就会根据表的引擎定义,去使用对应的引擎接口。
假设 user 表的 uid 字段没有索引,mysql系统调用InnoDB引擎接口获取表的第一行,判断uid是否等于1,如果不是则跳过,如果是则将结果存入结果集中。然后继续调用引擎接口取下一行,重复刚刚的判断直到表的最后一行。最后执行器将结果集返回给客户端。
假设 uid 字段有索引,mysql系统将通过索引直接定位到uid=1的行,将结果返回出来。

centos安装xdebug

centos 7

  1. 安装 pecl
    1.1 安装所需php扩展

$ rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
$ rpm -Uvh https://mirror.webtatic.com/yum/el7/webtatic-release.rpm

1.2 下载并安装PECL
//php版本 > 7

$ wget http://pear.php.net/go-pear.phar
$ php go-pear.phar

//php版本 < 7

$ yum install php-pear

1.3 把pecl添加到 PATH

$ cp /root/pear/bin/pecl /usr/bin

  1. 安装 xdebug
    2.1 解禁popen()函数
    在php.ini 找到 disable_functions = xxx, 删除popen并重启php-fpm

2.2 安装xdebug

$ pecl install xdebug

2.3 添加xdebug扩展到php.ini 并重启php-fpm
//具体拓展文件路径请参考安装完成后的说明

zend_extension=/usr/local/php/lib/php/extensions/no-debug-non-zts-20190902/xdebug.so

数据表的设计要点

  1. 数据行的长度不要超过8020字节,如果超过这个长度的话在物理页中这条数据会占用两行从而造成存储碎片,降低查询效率。

  2. 能够用数字类型的字段尽量选择数字类型而不用字符串类型的(电话号码),这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接回逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。

  3. 对于不可变字符类型char和可变字符类型varchar 都是8000字节,char查询快,但是耗存储空间,varchar查询相对慢一些但是节省存储空间。在设计字段的时候可以灵活选择,例如用户名、密码等长度变化不大的字段可以选择CHAR,对于评论等长度变化大的字段可以选择VARCHAR。

  4. 字段的长度在最大限度的满足可能的需要的前提下,应该尽可能的设得短一些,这样可以提高查询的效率,而且在建立索引的时候也可以减少资源的消耗。

限时秒杀系统设计要点

需求定义

在一定时间内,对一定数量的库存商品进行出售。

场景分析

  1. 在活动期间,对服务器的资源负载很高,如静态资源,商品信息,这些可以事先进行缓存,降低服务器负载。
  2. 防止用户进行刷单, 对uid或ip的访问频次进行限制,或者增加验证机制,如图形验证码,短信验证码等。
  3. 预备好中转界面,如稍后界面、排队中界面,避免直接卡页面对用户产生负面影响。

设计思路

前端

  • 页面静态化
  • 禁止重复提交

后端

  • 内存缓存
  • 负载均衡
  • 使用队列处理峰值请求
  • 异步处理
  • 结束后通知前端关闭入口,避免后续流量冲击

Jetbrains系列产品2019.3最新激活方法

大家熟知Jetbrains的话应该知道:他们家的所有产品升级到2018.2.1及以上版本后,先前可用的注册服务器都失效了,无法激活升级到最新版本体验最新黑科技。

这次要送的这份礼就是: Jetbrains全系列产品2019.3及以下版本(理论上适用于目前所有新老版本)最新注册服务器(License Server)的破解,可使用它来激活你手头上的Jetbrains IDE,具体支持产品和版本见下文的列表。

传送门:
百度云下载(baidu pan),提取码(password):u9rc。
OneDrive(download link)
sha1sum: bc6bd2fcfd5ac83fb0911018d13742660cf90965
具体使用方法已写在压缩包的 README.pdf / README.txt内(包内另附操作截图)。

转自

一个好玩的文章生成器

先贴链接
这玩意可以根据你输入的主题,生成一篇上万字的文章。虽然这篇文章狗屁不通,但是你不得不相信,他全文都在紧扣你设置的主题,并且可以把一些人绕进去。